package weathercrowd.managers;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;

import weathercrowd.model.*;

public class PersistenceManager {
	EntityManager em;
	
	public PersistenceManager(EntityManager em) {
		this.em = em;
	}
	
	public long generateUserId() {
		List<User> users = em.createQuery("select u from User u ORDER BY u.id").getResultList();
		long id = 1;
		for (User u : users) {
			if (u.getId() == id) {
				id++;
			} else {
				break;
			}
		}
		return id;
	}
	
	public long generateLocationId() {
		List<Location> locs = em.createQuery("select l from Location l ORDER BY l.id").getResultList();
		long id = 1;
		for (Location l : locs) {
			if (l.getId() == id) {
				id++;
			} else {
				break;
			}
		}
		return id;
	}
	
	public long generateRainfallId() {
		List<Rainfall> rfs = em.createQuery("select r from Rainfall r ORDER BY r.id").getResultList();
		long id = 1;
		for (Rainfall rf : rfs) {
			if (rf.getId() == id) {
				id++;
			} else {
				break;
			}
		}
		return id;
	}
	
	public long generateTemperatureId() {
		List<Temperature> ts = em.createQuery("select t from Temperature t ORDER BY t.id").getResultList();
		long id = 1;
		for (Temperature t : ts) {
			if (t.getId() == id) {
				id++;
			} else {
				break;
			}
		}
		return id;
	}
	
	public long generateEventId() {
		List<Event> es = em.createQuery("select e from Event e ORDER BY e.id").getResultList();
		long id = 1;
		for (Event e : es) {
			if (e.getId() == id) {
				id++;
			} else {
				break;
			}
		}
		return id;
	}
	
	public User getOrCreateUser(String email) {
		List<User> users = em.createQuery("select u from User u WHERE u.email=:email").setParameter("email", email).getResultList();
		if (users.size() > 0) {
			return users.get(0);
		}
		User user = new User();
		long id = generateUserId();
		user.setEmail(email);
		user.setId(id);
		em.persist(user);
		return user;
	}
	
	public List<Rainfall> getRainfalls(Date date) {
		return em.createQuery("select r from Rainfall r WHERE r.date=:date ORDER BY r.id").setParameter("date", date).getResultList();
	}
	
	public List<Temperature> getTemperatures(Date date) {
		return em.createQuery("select t from Temperature t WHERE t.date=:date ORDER BY t.id").setParameter("date", date).getResultList();
	}
	
	public List<BomLocation> getLocations(String bomId) {
		return em.createQuery("select l from BomLocation l WHERE l.bomId=:bomId ORDER BY l.id").setParameter("bomId", bomId).getResultList();
	}
	
	public List<Rainfall> getRainfalls(Date date, Location location) {
		return em.createQuery("select r from Rainfall r WHERE r.date=:date AND r.location=:location ORDER BY r.id")
				.setParameter("date", date).setParameter("location", location).getResultList();
	}
	
	public List<Temperature> getTemperatures(Date date, Location location) {
		return em.createQuery("select t from Temperature t WHERE t.date=:date AND t.location=:location ORDER BY t.id")
				.setParameter("date", date).setParameter("location", location).getResultList();
	}
	
	/**
	 * 
	 * @param start start of the date range inclusive
	 * @param end end of date rage inclusive
	 * @param location the location each of the record in the returned record set must be associated with
	 * @return
	 */
	public List<Rainfall> getRainfalls(Date start, Date end, Location location) {
		return em.createQuery("select r from Rainfall r WHERE r.date>=:start AND r.date<=:end AND r.location=:location ORDER BY r.date")
				.setParameter("start", start).setParameter("end", end).setParameter("location", location).getResultList();
	}
	
	/**
	 * @param start start of the date range inclusive
	 * @param end end of date rage inclusive
	 * @param location the location each of the record in the returned record set must be associated with 
	 * @return
	 */
	public List<Temperature> getTemperatures(Date start, Date end, Location location) {
		return em.createQuery("select t from Temperature t WHERE t.date>=:start AND t.date<=:end AND t.location=:location ORDER BY t.date")
				.setParameter("start", start).setParameter("end", end).setParameter("location", location).getResultList();
	}
	
	
	public String getRainfallMonthlyXml2(Date start, Date end, Location location) {
		List<Rainfall> rfs = getRainfalls(start, end, location);
		String xml = "";
		SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); 
		SimpleDateFormat formatter2 = new SimpleDateFormat("MMM/yyyy");
		xml += String.format("<graph caption=\"Monthly Rainfall Profile for %s\" ", location.getName());
		xml += String.format("subcaption=\"From %s to %s\" ", formatter.format(start), formatter.format(end));
		xml += "xAxisName=\"Date\" yAxisName=\"Rainfall\" showValues=\"0\" areaBorderColor=\"BCBF99\" areaBgColor=\"33FF00\" areaBorderThickness=\"1\" areaAlpha=\"90\" divlinecolor=\"BCBF99\" showAlternateHGridColor=\"1\" alternateHGridColor=\"BCBF99\" alternateHGridAlpha=\"10\" bgColor=\"E3E6D9\" bgAlpha=\"30\" baseFontColor=\"5D633F\" canvasBorderThickness=\"1\" decimalPrecision=\"0\" formatNumberScale=\"1\">\n";
		int lastMonth = -1;
		float sum = 0;
		String sDate = null;
		for (int i = 0; i < rfs.size(); i++) {
			Rainfall rf = rfs.get(i);
			Date date = rf.getDate();
			float value = rf.getAmount();
			if (value >= 99990) {
				int j1,j2;
				float v1=0, v2=0;
				for (j1 = i-1; j1>=0; j1--) {
					Rainfall r = rfs.get(j1);
					if (r.getAmount() < 99990) { v1 = r.getAmount(); break; }
				}
				for (j2 = i+1; j2<rfs.size(); j2++) {
					Rainfall r = rfs.get(j2);
					if (r.getAmount() < 99990) { v2 = r.getAmount(); break; }
				}
				value = (v1 + v2) /2;
			}
			int month = date.getMonth();
			if (lastMonth != -1 && month != lastMonth) {
				xml += String.format("  <set name=\"%s\" value=\"%f\"/>\r\n", sDate, sum);
				sum = value;
			} else {
				sum += value;
			}
			sDate = formatter2.format(date);
			lastMonth = month;
		}
		
		if (sDate != null) xml += String.format("  <set name=\"%s\" value=\"%f\"/>\r\n", sDate, sum);
		
		xml += "</graph>";
		return xml;
	}
	
	

	public String getRainfallMonthlyXml(Date start, Date end, Location location) {
		List<Rainfall> rfs = getRainfalls(start, end, location);
		String xml = "";
		SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); 
		SimpleDateFormat formatter2 = new SimpleDateFormat("MMM/yyyy");
		
		xml += String.format("<graph caption=\"Monthly Rainfall Profile for %s\" ", location.getName());
		xml += String.format("subcaption=\"From %s to %s\" ", formatter.format(start), formatter.format(end));
		xml += "xAxisName=\"Date\" yAxisName=\"Rainfall\" showValues=\"0\" areaBorderColor=\"BCBF99\" areaBgColor=\"33FF00\" areaBorderThickness=\"1\" areaAlpha=\"90\" divlinecolor=\"BCBF99\" showAlternateHGridColor=\"1\" alternateHGridColor=\"BCBF99\" alternateHGridAlpha=\"10\" bgColor=\"E3E6D9\" bgAlpha=\"30\" baseFontColor=\"5D633F\" canvasBorderThickness=\"1\" decimalPrecision=\"0\" formatNumberScale=\"1\">\n";
		
		
		String cate = "  <categories>\r\n";
		String values = "  <dataset seriesName=\"Rainfall\">\r\n";
		
		int lastMonth = -1;
		float sum = 0;
		String sDate = null;
		for (int i = 0; i < rfs.size(); i++) {
			Rainfall rf = rfs.get(i);
			Date date = rf.getDate();
			float value = rf.getAmount();
			if (value >= 99990) {
				int j1,j2;
				float v1=0, v2=0;
				for (j1 = i-1; j1>=0; j1--) {
					Rainfall r = rfs.get(j1);
					if (r.getAmount() < 99990) { v1 = r.getAmount(); break; }
				}
				for (j2 = i+1; j2<rfs.size(); j2++) {
					Rainfall r = rfs.get(j2);
					if (r.getAmount() < 99990) { v2 = r.getAmount(); break; }
				}
				value = (v1 + v2) /2;
			}
			int month = date.getMonth();
			if (lastMonth != -1 && month != lastMonth) {
				cate += String.format("    <category name=\"%s\"/>\r\n", sDate);
				values += String.format("    <set value=\"%f\"/>\r\n", sum);
				sum = value;
			} else {
				sum += value;
			}
			sDate = formatter2.format(date);
			lastMonth = month;
		}
		
		if (sDate != null) {
			cate += String.format("    <category name=\"%s\"/>\r\n", sDate);
			values += String.format("    <set value=\"%f\"/>\r\n", sum);
		}
		
		cate += "  </categories>\r\n";
		values += "  </dataset>\r\n";
		
		xml += cate;
		xml += values;

		xml += "</graph>";
		return xml;
	}
	
	public String getTemperatureMonthlyXml(Date start, Date end, Location location) {
		List<Temperature> tmprs = getTemperatures(start, end, location);
		String xml = "";
		SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); 
		SimpleDateFormat formatter2 = new SimpleDateFormat("MMM/yyyy");
		
		xml += String.format("<graph caption=\"Monthly Temperature Profile for %s\" ", location.getName());
		xml += String.format("subcaption=\"From %s to %s\" ", formatter.format(start), formatter.format(end));
		xml += "xAxisName=\"Date\" yAxisName=\"Temperature\" showValues=\"0\" areaBorderColor=\"BCBF99\" areaBgColor=\"FFCC00\" areaBorderThickness=\"1\" areaAlpha=\"90\" divlinecolor=\"BCBF99\" showAlternateHGridColor=\"1\" alternateHGridColor=\"BCBF99\" alternateHGridAlpha=\"10\" bgColor=\"E3E6D9\" bgAlpha=\"30\" baseFontColor=\"5D633F\" canvasBorderThickness=\"1\" decimalPrecision=\"0\" formatNumberScale=\"1\">\r\n";
	
		String cate = "  <categories>\r\n";
		String minset = "  <dataset seriesName=\"Minimum Temperature\">\r\n";
		String maxset = "  <dataset seriesName=\"Maximum Temperature\">\r\n";
		int lastMonth = -1;
		float avgmin = 0;
		float avgmax = 0;
		int count = 0;
		String sDate = null;
		
		for (int i = 0; i < tmprs.size(); i++) {
			Temperature tmpr = tmprs.get(i);
			Date date = tmpr.getDate();
			float min = tmpr.getMin();
			float max = tmpr.getMax();
			if (min >= 99990) {
				int j1,j2;
				float v1=0, v2=0;
				for (j1 = i-1; j1>=0; j1--) {
					Temperature t = tmprs.get(j1);
					if (t.getMin() < 99990) { v1 = t.getMin(); break; }
				}
				for (j2 = i+1; j2<tmprs.size(); j2++) {
					Temperature t = tmprs.get(j2);
					if (t.getMin() < 99990) { v2 = t.getMin(); break; }
				}
				min = (v1 + v2) /2;
			}
			if (max >= 99990) {
				int j1,j2;
				float v1=0, v2=0;
				for (j1 = i-1; j1>=0; j1--) {
					Temperature t = tmprs.get(j1);
					if (t.getMax() < 99990) { v1 = t.getMax(); break; }
				}
				for (j2 = i+1; j2<tmprs.size(); j2++) {
					Temperature t = tmprs.get(j2);
					if (t.getMax() < 99990) { v2 = t.getMax(); break; }
				}
				max = (v1 + v2) /2;
			}
			int month = date.getMonth();
			if (lastMonth != -1 && month != lastMonth) {
				avgmin /= count;
				avgmax /= count;
				cate += String.format("    <category name=\"%s\"/>\r\n", sDate);
				minset += String.format("    <set value=\"%f\"/>\r\n", avgmin);
				maxset += String.format("    <set value=\"%f\"/>\r\n", avgmax);
				avgmin = min;
				avgmax = max;
				count = 1;
			} else {
				avgmin += min;
				avgmax += max;
				count++;
			}
			sDate = formatter2.format(date);
			lastMonth = month;
		}
		
		cate += "  </categories>\r\n";
		minset += "  </dataset>\r\n";
		maxset += "  </dataset>\r\n";
		
		xml += cate;
		xml += minset;
		xml += maxset;
		
		xml += "</graph>";
		return xml;
	}
	
}
